home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Rotation-c / ROT-PSIG .c next >
Text File  |  1994-06-03  |  20KB  |  592 lines

  1. //• ------------------------------------------------------------------- •//
  2. //• Another public domain C example source demo, brought back from        •//
  3. //• the dead at:  itty bitty bytes™ - by Kenneth A. Long!                •//
  4. //• Made to run in Think C™ on 2 June 1994.                                •//
  5. //• Uses no resource file - just add MacTraps and ANSI libraries.        •//
  6. //• The original of this file was found on ftp.cso.uiuc.edu in mac/MUG. •//
  7. //• ------------------------------------------------------------------- •//
  8.  
  9. //• 3D Demonstration  (DRAFT)
  10. //• as told in Megamax C V2.1
  11. //• by
  12. //• M H Miller         ... 30 March 1986.
  13.  
  14. //• wire frame                     10 April 1986.
  15. //• rotations                    15 April 1986.
  16. //• visibility                     1 May   1986.
  17. //• touchup                         3 May   1986.
  18. //• add 1st order lighting         8 May   1986.
  19.             
  20. //• This is an 'application' which eventually will take its proper 
  21. //• place among a set of exercises whose purpose is enhancing 
  22. //• understanding of C programming (Megamax C is the particular vehicle 
  23. //• used), and in facilitating oozing through Inside Macintosh.  In 
  24. //• most of these exercises the methodology is to explore a  number 
  25. //• of Inside Macintosh functions and procedures, observe their visual 
  26. //• effects (if any), study their syntax, and in general evaluate their 
  27. //• use and usfulness in the Macintosh interface.    Modifications, 
  28. //• enhancements, non_commercial uses of this material, and tactful 
  29. //• comments are invited, indeed encouraged.
  30.  
  31. //• In studying the exercise (s) keep in mind (for my sake at least) 
  32. //• that the principal intention is not to optimize the operation (s) 
  33. //• performed but rather to examine Macintosh operations and C 
  34. //• programming.  With that view what you don't care for should be 
  35. //• considered an objective illustration of what not to do.
  36.         
  37. //• --------------------------------------------------------  
  38. //• This exercise involves computation of the isometric projection of a 
  39. //• solid and rotation of that solid about an axis.  The character of 
  40. //• the solid is constrained so that particular  circumstances requiring 
  41. //• extended computation and manipulation are avoided.  Specifically the 
  42. //• solid must have plane faces which are closed polygons.  The solid 
  43. //• must be 'convex', i.e., the  angle between outward normals to two 
  44. //• contiguous faces must be greater than 90 degrees; this eliminates 
  45. //• solids with 'holes', indentations, or 'pimples'.    For a convex 
  46. //• solid a face either is visible in its entirety or it isn't; there 
  47. //• is no 'shadowing' of one face by others.    Rotations of the solid 
  48. //• are about a single (coordinate) axis at a time for illustrative 
  49. //• simplicity, although generalizing is not all that difficult or 
  50. //• involved.    For each rotated position an equiangular isometric 
  51. //• projection is computed.  In addition the orientation of each face 
  52. //• of a projection is  computed to determine if the outward normal of 
  53. //• a projected face points into or out of the screen; a face is visible 
  54. //• looking into the screen if its outward normal points out of the 
  55. //• screen.  A dynamic presentation of the rotating solid is drawn, 
  56. //• optionally either as a wire frame or as a solid.  Additional 
  57. //• variations are planned for addition now and then.
  58.  
  59. //• NOTE 1: The nature of the data structures used is of some importance.  
  60. //• However no great emphasis was placed on optimizing these in this 
  61. //• illustration.  Consider this illustration to be an illustration and 
  62. //• not a 'how to' prescription.  Nevertheless the program is written to 
  63. //• allow easy redefinition of  the object rotated, within the simplifying 
  64. //• constraints noted.
  65.  
  66. //• NOTE 2: This is a 'brute force' version to provide a reference against 
  67. //• which to evaluate the efficacy of measures to reduce flickering and 
  68. //• image discontinuity.  Some modifications to be added sooner or later 
  69. //• are bitmap switching, assembly language interventions, synchronizing 
  70. //• to the blanking interrupts, and cleaning the screen as a VBL task.
  71. //• --------------------------------------------------------.    
  72.  
  73. #include <stdio.h>    
  74. #include <math.h>
  75.  
  76. //typedef  int void;    //• Thoroughly Modern Miller.
  77.  
  78. #define X 0                //• Axis references.
  79. #define Y 1
  80. #define Z 2 
  81.  
  82. //• For simplicity the object to be drawn is predefined.  The 
  83. //• specification is for the 'base' position from which all rotated 
  84. //• positions are computed.  Within the constraints on the type of 
  85. //• object allowed a new object can be redefined by redefining the 
  86. //• parameters asdescribed or readily inferred.  The following three 
  87. //• parameters are used to set computation loop limits; redefine to suit.
  88.     
  89. #define  NMBR_FACES 9
  90. #define  NMBR_VERTICES 9
  91. #define  NMBR_SETS 20        //• rotation angle step == 360 / NMBR_SETS.
  92.  
  93.  
  94. //• Object vertex coordinates (relative to vertex 0).  This example is 
  95. //• for a regulartrapazoidal parallelpiped.  This part of the 
  96. //• specification only partially defines thesolid; still to come is 
  97. //• specification of the face edges, i.e., the connections between
  98. //• vertices which  define the individual faces.  Dimensions are 
  99. //• referenced to LX, LY, and LZ.  Note that rotations will be about 
  100. //• coordinate axes for simplicity.  However that does not constrain 
  101. //• the initial orientation of the object; it can be 'tilted' as desired.
  102.  
  103. #define LX 80
  104. #define LY 40
  105. #define LZ 60
  106.     
  107. //•    #####################################
  108. //• (Try using this vertex table, and comment out the other one - K.A.L.)
  109. //• 'Plain Jane' initial orientation (not used)
  110. /*
  111. int vertex [NMBR_VERTICES] [3] = 
  112. {        
  113.     {            0,        0,             0 }, 
  114.     {            0,        0,            LZ }, 
  115.     {           LX,        0,            LZ },     
  116.     {           LX,        0,             0 },     
  117.     { 3 * LX / 4,       LY,        LZ / 4 },     
  118.     { 3 * LX / 4,       LY, 3 * LZ / 4 },     
  119.     {       LX / 4,        LY, 3 * LZ / 4 },     
  120.     {      LX / 4,        LY,        LZ / 4 }, 
  121.     {      LX / 2, -LY / 2,        LZ / 2 }
  122. };
  123. */
  124. //• ####################################
  125.     
  126.     
  127. //• 'Centerfold' (more exposed) initial position; 
  128. //• scale not the same as for Plain Jane.  
  129. //• This is the specification used for the program.
  130.  
  131. int vertex [NMBR_VERTICES] [3] = 
  132. {            
  133.     {            0,         0,       LZ / 2 }, 
  134.     {       LX / 2,         0,           LZ },     
  135.     {           LX,         0,       LZ / 2 }, 
  136.     {       LX / 2,         0,            0 }, 
  137.     {      LX / 2,        LY,       LZ / 4 },     
  138.     { 3 * LX / 4,        LY,       LZ / 2 },     
  139.     {      LX / 2,        LY, 3 * LZ / 4},     
  140.     {      LX / 4,        LY,       LZ / 2 }, 
  141.     {      LX / 2, -LY / 2,       LZ / 2 }
  142. };    
  143.  
  144.  
  145. //• A face is defined its edges; in turn these are defined by a set 
  146. //• of vertices.  The vertex list is determined as follows:    
  147.  
  148. //• a) Imagine the outward normal to the surface to be drawn. 
  149.  
  150. //• b) Imagine your right hand curled around the normal, thumb 
  151. //• pointing outward from theface along the normal.
  152.  
  153. //• c) Follow the curl of your fingers in listing the vertices 
  154. //• forming the face edges.  Note that the last vertex listed is 
  155. //• the same as the first one; any of the face vertices maybe 'first' 
  156. //• in the list.  
  157.     
  158. //• The number of vertices need not be the same for all faces.  Note 
  159. //• again that faces are required to be planar polygons.  Violation 
  160. //• of this constraint generally shows up as overlapping faces as
  161. //• the object rotates.The following 'face' specification is for the 
  162. //• trapazoidal pyramid.  Per standard C rules any array elements not 
  163. //• specified will be set to 0, although this is not important since 
  164. //• they are not used at all.
  165.  
  166. int  face [NMBR_FACES] [5] = 
  167. {     
  168.     {0, 1, 6, 7, 0}, 
  169.     {1, 2, 5, 6, 1}, 
  170.     {2, 3, 4, 5, 2}, 
  171.     {7, 4, 3, 0, 7}, 
  172.     {7, 6, 5, 4, 7}, 
  173.     {0, 3, 8, 0}, 
  174.     {8, 1, 0, 8}, 
  175.     {8, 2, 1, 8}, 
  176.     {8, 3, 2, 8}
  177. };
  178.         
  179. //• Define the coordinates xr, yr of the center of rotation/origin (this 
  180. //• will be taken to be somewhere in the plane of the screen), and the 
  181. //• offset of vertex 0 from the center of rotation (dxo, dyo, dzo).     
  182. //• Thus the absolute location of, say the X-coordinate of vertex 4, is 
  183. //• xr + dxo + vertex [4] [X].    See below for the computation of 
  184. //• projection coordinates.
  185.  
  186.  int  xr = 200, yr = 160, zr = 0, dxo = 50, dyo = 30, dzo = -50;    
  187.  
  188. //• For each face a polygon will be computed (later) for the 
  189. //• projection of that face.
  190. PolyHandle  face_poly [NMBR_SETS] [NMBR_FACES];
  191.  
  192. //• For each face, and in each set the direction of the normal to a 
  193. //• projected face is computed to determine if that face is visible 
  194. //• or not.  In addition the illumination (yes or no) of a face from 
  195. //• a source to the left and up is determined.
  196.  
  197. short visible [NMBR_SETS] [NMBR_FACES];    
  198. short light [NMBR_SETS] [NMBR_FACES];    
  199.  
  200. short drawflag;    //• Switch between drawing types.  SOLID illustrates 
  201.                 //• the use of the 'visibility'computation, i.e., only 
  202.                 //• 'visible' faces are drawn.  SOLID_LIGHT adds 
  203.                 //• first-order illumination.
  204.  
  205. #define SOLID_LIGHT 0
  206. #define SOLID  1
  207. #define WIRE_FRAME 2
  208.  
  209. Rect option_rect, display_rect;        //• Housekeeping.
  210.  
  211. WindowPtr    newWindow;                            //• Added by K.A.L.
  212. Rect        dragRect;                            //• Added by K.A.L.
  213. Rect        windowBounds = { 20, 0, 384, 512};    //• Added by K.A.L.
  214.  
  215. //• Prot's:
  216. int main (void);
  217. void Compute_Rotation_Data (int axis);
  218. void Rotate_Object (void);
  219.  
  220. main ()                        
  221. {    
  222.     EventRecord the_event;
  223.     Point mousepoint;
  224.     GrafPtr the_port;
  225.     int i, j;
  226.     register int  this_set, next_set;
  227.     Rect temp_rect;
  228.     
  229.     InitGraf (&thePort);     
  230.     InitFonts ();    
  231.     InitWindows ();    
  232.     InitCursor ();
  233.     
  234.     //• The next 3 lines was added by K.A.L. because...
  235.     
  236.     dragRect = qd.screenBits.bounds;    
  237.     
  238.     newWindow = NewWindow (0L, &windowBounds, "\p", true, 
  239.                             noGrowDocProc, (WindowPtr) -1L, true, 0);
  240.     SetPort (newWindow);
  241.  
  242.     //• ...the next 6 lines messed things up.
  243.     
  244.     //• Use the window manager port (desktop) directly.  
  245.     //• Open up the clipregion to include themenu bar and clear the screen.  
  246.     //• Define a housekeeping rectangle for erasing the screen.
  247.     
  248. //    GetWMgrPort (&the_port);
  249. //    SetPort (the_port);
  250. //    ClipRect (& (the_port->portRect));
  251. //    EraseRect (& (the_port->portRect));
  252. //    SetOrigin (0, 0);
  253.  
  254.     //• K.A.L. made the following be windowBounds (above).
  255. //    SetRect (&display_rect, 0, 21, 512, 342);
  256.     
  257.     //• Startup with SOLID_LIGHT, X-axis rotation.
  258.     Compute_Rotation_Data (X);
  259.       drawflag = SOLID_LIGHT;
  260.     
  261.  
  262.     for (;;)
  263.     {    
  264.         GetNextEvent (everyEvent, &the_event);
  265.         if (the_event.what == mouseDown )
  266.         {    
  267.             GetMouse (&mousepoint);
  268.         
  269.             if (PtInRect (mousepoint, &option_rect) ) 
  270.             {    
  271.                 switch (i = mousepoint.h / 15)
  272.                 {    
  273.                     case 0:                //• Q for QUIT.
  274.                         exit (0);    
  275.                     break;
  276.                 
  277.                     case 1: 
  278.                     case 2:  
  279.                     case 3:    //• Rotate X, Y, Z respectively.
  280.                         Compute_Rotation_Data (i-1);
  281.                     break;
  282.                 
  283.                     case 4:                //• SOLID, SOLID_LIGHT, WIRE_FRAME.
  284.                         if (++drawflag == 3)     drawflag = 0;
  285.                     break;    
  286.                 }
  287.             } 
  288.             else 
  289.                 while (Button ())    ; //• Freeze frame.
  290.         }
  291.         Rotate_Object ();            //• Take a step.
  292.     }
  293. }
  294.  
  295. //• The isometric projection is an equiangular proection on the 
  296. //• plane (screen).  The y-axis coordinate of a point is drawn 
  297. //• vertically (+ down) from the origin.  The x-axis position is 
  298. //• along a Line drawn 30 degrees down from horizontal, while the 
  299. //• z-axis is drawn along a  Line elevated 30 degrees above the 
  300. //• horizontal.    The net result is that the screen position relative 
  301. //• to the origin of the point x, y, z is (in screen position 
  302. //• coordinates) (x, y) = (x + z) * cos (30), y + (x - z) * sin (30) 
  303. //• This procedure computes the rotated position of the vertices, 
  304. //• computes whether a  projected face is 'visible' or not, and 
  305. //• defines polygons for each face in each projection. The data 
  306. //• produced is 'face_poly [this_set] [i]' which  is the polygon 
  307. //• for drawing face #i after a rotation of 360 * this_set / NMBR_SETS.  
  308. //• No indication provided for axis of rotation.  In addition 
  309. //• 'visible [this_set] [i]' =1/0 indicates that face is visible / invisible 
  310. //• seen looking into the screen. 
  311.  
  312. //• Note:  The only global parameters provided by this illustrative 
  313. //• computation are the polygon  handles and the 'visibility' and 
  314. //• 'light' arrays.
  315. void Compute_Rotation_Data (int axis)
  316. {
  317.     register int this_set, i, j;    //• Rotation angle is 360 * this_set / NMBR_SETS.
  318.     int  basev [NMBR_VERTICES] [3];    //• Vertex coordinates offset from center of rotation.
  319.     int v [NMBR_VERTICES] [3];        //• Vertex rotated coordinates.
  320.     int p_vx [NMBR_VERTICES], p_vy [NMBR_VERTICES];  //• Projection coordinates.
  321.     int ax, ay, az, bx, by, bz;        //• Vector components for computing direction cosines.
  322.     
  323.     //• Miscellaneous utility variables•//
  324.     Rect count_rect;                
  325.     int v0, v1, v2;
  326.     float sin_table, cos_table; 
  327.     #define D_THETA  6.283185 / NMBR_SETS
  328.     
  329.     //• Cf Psych 100 notes.
  330.     SetRect (&count_rect, 0, 21, 512, 342);    
  331.     EraseRect (&count_rect);
  332.     TextSize (18); 
  333.     TextFace (bold); 
  334.     TextFont (geneva); 
  335.     PenNormal ();
  336.     MoveTo (200, 150);    
  337.     DrawString ("\pHOLD ON");
  338.     MoveTo (50, 170);    
  339.     DrawString ("\pI'M COMPUTING WHAT I NEED TO KNOW");
  340.     
  341.     //• Compute the rotated position of the vertices.  Note that the 
  342.     //• computation references the base vertex definitions for each 
  343.     //• computation rather than accumlating incremental rotations.  
  344.     //• For real time rotation computations the latter would be 
  345.     //• appropriate, provided regular reinitialization, direct or 
  346.     //• indirect, avoided error accumulation.
  347.     
  348.     //• Locate vertices relative to center of rotation.
  349.     for (i = 0; i < NMBR_VERTICES; ++i)    
  350.     {    
  351.         basev [i] [X] = vertex [i] [X]  + dxo;    
  352.         basev [i] [Y] = vertex [i] [Y]  + dyo;    
  353.         basev [i] [Z] = vertex [i] [Z]    + dzo;
  354.     }
  355.     
  356.     //• Angular increment is 360 / NMBR_SETS.
  357.     for (this_set = 0; this_set < NMBR_SETS; ++this_set)    
  358.     {                                         //• Convenience variables.
  359.         sin_table  =  sin (D_THETA * this_set);    
  360.         cos_table = cos (D_THETA * this_set);    
  361.         
  362.     //• Rotate the vertices.  Note that the coordinates are relative to the center of rotation.•//
  363.         for (i=0;i<NMBR_VERTICES;++i)    
  364.         {    
  365.             switch (axis)    
  366.             {    case Z:    
  367.                     v [i] [X] = basev [i] [X] * 
  368.                               cos_table - basev [i] [Y] *
  369.                               sin_table;
  370.                               
  371.                     v [i] [Y] = basev [i] [X] *
  372.                               sin_table + basev [i] [Y] *
  373.                               cos_table;
  374.                               
  375.                     v [i] [Z] = basev [i] [Z];
  376.                 break;
  377.                 
  378.                 case Y:    
  379.                     v [i] [X] = basev [i] [X] * 
  380.                               cos_table + basev [i] [Z] * sin_table;
  381.                               
  382.                     v [i] [Y] = basev [i] [Y];
  383.                     v [i] [Z] = -basev [i] [X] * 
  384.                               sin_table + basev [i] [Z] * cos_table;
  385.                 break;
  386.                 
  387.                 case X:    
  388.                     v [i] [X] = basev [i] [X];
  389.                     v [i] [Y] = basev [i] [Y] * 
  390.                               sin_table +  basev [i] [Z] * cos_table;
  391.                     v [i] [Z] = -basev [i] [Y] * 
  392.                               cos_table +  basev [i] [Z] * sin_table;
  393.                     break;
  394.             }
  395.         }
  396.         
  397.         //• A source of light is assumed far away and to the right.  A 
  398.         //• face is illuminated if 'sees'the light, i.e., if its outward 
  399.         //• normal is directed to the right.  In addition of course
  400.         //• the face will have to be visible in the projection, as 
  401.         //• computed later.  This illumination algorithm does not 
  402.         //• provided graded lighting as would occur in reality.  A 
  403.         //• face either is or is not illuminated. 
  404.         
  405.         //• Note: See comments below for 'visible' computation for 
  406.         //• additional pertinent remarks not included here. 
  407.         for (i = 0; i < NMBR_FACES; ++i)
  408.         {    
  409.             v0 = face [i] [0];        
  410.             v1 = face [i] [1];    
  411.             v2 = face [i] [2];    
  412.             ay = v [v2] [Y] -  v [v1] [Y];    
  413.             by = v [v0] [Y] -  v [v1] [Y];
  414.             az =  v [v2] [Z] -  v [v1] [Z];    
  415.             bz =  v [v0] [Z] -  v [v1] [Z];
  416.         
  417.             //• An illuminated face has a 0 flag..
  418.             light [this_set] [i] = (ay * bz - az * by) > 0 ?0 :1;    
  419.         }
  420.         
  421.         //• Compute the isometric positions for each vertex in the 
  422.         //• current set.  The projection is computed relative to the 
  423.         //• center of rotation as origin and then reset relative to 
  424.         //• the screen origin.
  425.         for (i = 0; i < NMBR_VERTICES; ++i)
  426.         {    
  427.             p_vx [i] = xr + .86603 * (v [i] [X] + v [i] [Z]);
  428.             p_vy [i] = yr +  v [i] [Y] + (v [i] [X] - v [i] [Z])/2;
  429.         }    
  430.         
  431.         //• A face of the projection is 'visible' if it can be seen 
  432.         //• looking into the screen.  To determine visibility use the 
  433.         //• fact that faces are defined by the array face [] [4]  which 
  434.         //• provides the clockwise sequence of vertices defining the 
  435.         //• face.  The procedure is:     
  436.         
  437.         //• a) Select three consecutive 
  438.         //• vertices #0, #1, #2 from the face definition vector to 
  439.         //• define two projected face edges.  The first three are used.  
  440.         //• Note that the face definition vector lists vertices 
  441.         //• circulating CCW about outward directed normal. 
  442.         
  443.         //• b) Define edge#1 as fron vertex #1 to vertex #2; call this 
  444.         //• edge A. 
  445.         
  446.         //• c) Define edge#2 as fron vertex #1 to vertex #0; call this 
  447.         //• edge B. 
  448.         
  449.         //• d) The normal is A x B = Ax * By - Ay * Bx; 
  450.         //• if this is negative (out of the screen) the face is visible.
  451.         
  452.         //• Note: Notational guide: The first three vertices of face #
  453.         //• this_set are face [this_set] [0], face [this_set] [1], and  
  454.         //• face [this_set] [2].  Compute components as:     
  455.         //• Ax = v [face [this_set] [2]] [X] -  
  456.         //•      v [face [this_set] [1]] [X] ;        
  457.         //• Bx = v [face [this_set] [0]] [X] -  
  458.         //•      v [face [this_set] [1]] [X] ;    
  459.         //• The fact that the vertex coordinates are relative to the 
  460.         //• center of rotation washes out because of the difference is 
  461.         //• taken. 
  462.         
  463.         for (i = 0; i < NMBR_FACES; ++i)
  464.         {    
  465.             v0 = face [i] [0];        
  466.             v1 = face [i] [1];    
  467.             v2 = face [i] [2];    
  468.             ax = p_vx [v2] -  p_vx [v1];    
  469.             bx = p_vx [v0] -  p_vx [v1];
  470.             ay = p_vy [v2] -  p_vy [v1];    
  471.             by = p_vy [v0] -  p_vy [v1];
  472.         
  473.             //• Condition a flag  'visible [this_set] [i]' to indicate
  474.             //•  visible faces.. 
  475.             visible [this_set] [i] =     (ax * by - ay * bx) < 0 ?1 :0;
  476.         }
  477.         
  478.         //• Compute the face polygons.  Note that restriction to 
  479.         //• convex solids means a face either is visible or it is not; 
  480.         //• no partial visibility because of shadowing.
  481.         for (i = 0; i < NMBR_FACES; ++i)
  482.         {    
  483.             face_poly [this_set] [i] = OpenPoly ();
  484.                 MoveTo (p_vx [face [i] [0]], p_vy [face [i] [0]]  );
  485.                 for (j = 1; j < NMBR_VERTICES; ++j)
  486.                 {    
  487.                     LineTo (p_vx [face [i] [j]], p_vy [face [i] [j]]  );
  488.                     if (face [i] [j] == face [i] [0]  )    
  489.                         break;
  490.                 }
  491.                 ClosePoly ();
  492.             }
  493.         
  494.             //• Display computational progress as a countdown.
  495.             SetRect (&count_rect, 200, 175, 250, 205);
  496.             EraseRect (&count_rect);
  497.             MoveTo (210, 200);
  498.             i = (NMBR_SETS-this_set); 
  499.             if (i > 99)    
  500.                 DrawChar (48 + i / 100);    
  501.             else    
  502.                 DrawChar (' '); 
  503.             
  504.             if (i > 99)  
  505.             { 
  506.                 i %= 100;      
  507.                 DrawChar (48 + i / 10);  
  508.                 i %= 10 ;  
  509.             }    
  510.             else
  511.                 {    
  512.                     if (i>9)    
  513.                     {
  514.                         DrawChar (48 + i / 10);    
  515.                         i %= 10;  
  516.                     } 
  517.                     else  
  518.                         DrawChar (' '); 
  519.             }    
  520.             DrawChar (48+i);
  521.         }
  522.         
  523.         //• Draw 'option bar'.
  524.         TextSize (12);    
  525.         SetRect (&option_rect, 0, 0, 76, 20);    
  526.         FrameRect (&option_rect);
  527.         
  528.         MoveTo (5, 16);    
  529.         DrawChar ('Q');    
  530.         
  531.         MoveTo (0, 15);    
  532.         Line (0, 15);
  533.         
  534.         MoveTo (20, 16);    
  535.         DrawChar ('X');
  536.         
  537.         MoveTo (0, 30);    
  538.         Line (0, 15);
  539.         
  540.         MoveTo (35, 16);    
  541.         DrawChar ('Y');    
  542.         
  543.         MoveTo (0, 45);    
  544.         Line (0, 15);
  545.         
  546.         MoveTo (50, 16);    
  547.         DrawChar ('Z'); 
  548.             
  549.         MoveTo (0, 60);    
  550.         Line (0, 15);
  551.         
  552.         MoveTo (65, 16);    
  553.         DrawChar ('F');
  554. }
  555.     
  556. void Rotate_Object ()
  557. {    
  558.     register int i;    
  559.     static int set = 0;
  560.     register PolyHandle *poly;
  561.     
  562.     poly = &face_poly [set] [0];
  563.     
  564.     EraseRect (&display_rect);
  565.     if (drawflag == SOLID_LIGHT)  
  566.     {    
  567.         for (i=0;i<NMBR_FACES;++i)    
  568.         {    
  569.             if (visible [set] [i] ==1) 
  570.             {    
  571.                 if (light [set] [i] ==1)     
  572.                     FillPoly (* (poly + i), <Gray);
  573.                     FramePoly (* (poly + i)); 
  574.             }    
  575.         }
  576.     }
  577.     else 
  578.         if (drawflag == SOLID)  
  579.         {    
  580.             for (i = 0; i < NMBR_FACES; ++i)    
  581.                 if (visible [set] [i] ==1)    
  582.                     FramePoly (* (poly + i)); 
  583.         }
  584.         else     
  585.             for (i = 0; i < NMBR_FACES; ++i)    
  586.                 FramePoly (* (poly + i)); 
  587.     
  588.     if (++set == NMBR_SETS )    
  589.         set = 0;     //• Update the rotation angle.
  590. }
  591.  
  592.